package com.aaa.jvmtest.gcmanagement;

import java.io.IOException;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;

/**
 * 演示引用 设置堆内存参数：-Xmx20m，及打印垃圾回收详细信息参数：-XX:+PrintGCDetails -verbose:gc
 * 软引用（当没有强引用直接引用时，且发生垃圾回收后内存还是不够，此时回收软引用对象）
 * 弱引用（当没有强引用直接引用时，回收弱引用对象）
 *
 * @author Tu
 * @date 2022/7/2 16:22
 */
public class ReferencesShow {

    private static final int _4M = 4 * 1024 * 1024;

    /**
     * （软、弱引用）首先前提是：对象没有被没有强引用引用
     */
    public static void main(String[] args) {
        try {
            //strongReferences();
            //softReferences();
            weakReferences();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 使用强引用内存不足会造成 Java-heap-space OutOfMemoryError，内存溢出
     */
    public static void strongReferences() throws IOException {
        List<byte[]> list = new ArrayList<>();
        for (int i = 0; i < 5; i++) {

            list.add(new byte[_4M]);
        }
        System.in.read();
    }

    /**
     * 使用软引用不会出现内存溢出，当发生垃圾回收后内存不足，会回收软引用中的对象
     * 第四次循环内存紧张，释放了新生代内存[PSYoungGen: 2218K->488K(6144K)]
     * 第五次内存仍然不够，触发 full GC 回收新生、老年代内存仍不够；触发软引用，清除软引用引用的对象，这时候软引用对象引用对象为null
     * 第五次再创建新的软引用对象、及再添加新的引用对象(前四个byte数组都被清除)
     */
    public static void softReferences() throws IOException {
        //软引用对象实现方式  list -> SoftReference -> byte[]
        //声明集合
        List<SoftReference<byte[]>> list = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            System.out.println("--第" + (i + 1) + "次循环--");
            //创建软引用对象,并引用byte数组对象
            SoftReference<byte[]> softReference = new SoftReference<>(new byte[_4M]);
            //get 获取软引用内部对象
            System.out.println(softReference.get());
            list.add(softReference);
        }
        System.out.println("循环结束" + list.size());
        for (SoftReference<byte[]> softReference : list) {
            //获取软引用引用的对象
            System.out.println(softReference.get());
        }
    }

    /**
     * 当内存不足，触发垃圾回收，内存不足会尝试将弱引用引用的对象清除，避免强引用造成的内存溢出
     * 发生垃圾回收时内存不足会清除前面的弱引用引用的对象，直到能放下当前对象(不清除完)
     * 但其本身也是有一定内存，所以当内存仍然不足会触发full GC，届时所有弱引用引用的对象都会被清除
     * 也可配合引用队列使用
     */
    public static void weakReferences() {
        //弱引用对象实现方式  list -> WeakReference -> byte[]
        //声明集合
        List<WeakReference<byte[]>> list = new ArrayList<>();
        for (int i = 0; i < 6; i++) {
            System.out.println("--第" + (i + 1) + "次循环--");
            //创建软引用对象,并引用byte数组对象
            WeakReference<byte[]> weakReference = new WeakReference<>(new byte[_4M]);
            System.out.println(weakReference.get());
            list.add(weakReference);
        }
        System.out.println("循环结束" + list.size());
        for (WeakReference<byte[]> weakReference : list) {
            //获取软引用引用的对象
            System.out.println(weakReference.get());
        }
    }

}
